Some client/server based applications implement a Remote Procedure Call (RPC) protocol that provides an abstract communication mechanism for a client to request a procedure execution on a remote server. Notably, by decoupling the client and server functionality from the transport mechanism, RPC allows a client to access a server that is connected via a network without knowledge of the transport mechanism. RPC services are usually agnostic of the programming language in which a client may be implemented. Accordingly, major service vendors often provide a client library or a software development kit (SDK) that simplifies the usage of the exposed service on a specific language platform. Such libraries often offer an object-oriented programming (OOP) interface for dealing with the remote service and hide the actual request/response message complexity. For each language that is directly supported by the service, an application programming interface (API) exposes the methods and data types that are implemented by the service. For instance, an SDK provided by a particular service may include a Java API and a C# API, enabling clients written in Java and C# respectively to easily access the service across the connecting network irrespective of the language in which the service is written. Such APIs are often pre-generated based on RPC service metadata description that can be utilized for the creation of the server and the client implementations. These APIs are aware of the data types that the service supports and eliminate the requirement of sending type metadata with each RPC message—an undesirable overhead.
However, such pre-generated APIs are constrained by the features supported by the languages in which they are written. Consequently, while generated APIs may be effectively implemented in statically-typed languages, comprehensively implementing APIs written in dynamically-typed languages, such as JavaScript and Python may be problematic. In particular, without support for static typing, such pre-generated APIs cannot utilize type introspection (also known as reflection)—the ability to examine and modify programs at runtime—thus limiting the extraction of the required service metadata. Pre-generated APIs are usually mandatory for compiled languages since the compiler program requires physical access to the linked interfaces. Interpreted languages, on the other hand, may allow on-the-fly generation of such APIs when it happens before their initial usage.
In one approach to reducing the limitations of generated APIs for dynamically-typed languages, the generated API includes data type information in a non-native format. While such an approach may adequately capture basic functionality, the size of the API required to specify the functionality provided by a service with substantial capabilities is unacceptable large, particularly for browser-based applications. In one example, the compressed prototype of an enriched (i.e., including customized type information) web service API that exposes virtual machine management software to client applications includes 40 MB of generated JavaScript. In another approach, a middle-tier written in a statically-typed language provides a language bridge that allows clients written in dynamically-typed languages to indirectly access the service. However, the middle-tier not only complicates the creation of the client application, but also increases the time required to execute the application. Consequently, there is a need for an improved dynamically-typed API generation technique.